<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>D365 Data Search Page</title>
    <style>
        :root {
            --primary-color: #1976d2;
            --primary-dark: #115293;
            --primary-light: #42a5f5;
            --error-color: #d32f2f;
            --warning-color: #ed6c02;
            --info-color: #0288d1;
            --success-color: #2e7d32;
            --text-primary: rgba(0, 0, 0, 0.87);
            --text-secondary: rgba(0, 0, 0, 0.6);
            --divider-color: rgba(0, 0, 0, 0.12);
            --background-paper: #fff;
            --background-default: #f5f5f5;
            --grey-50: #fafafa;
            --grey-100: #f5f5f5;
            --grey-200: #eeeeee;
            --grey-300: #e0e0e0;
            --grey-400: #bdbdbd;
            --shadow-1: 0px 2px 1px -1px rgba(0,0,0,0.2), 0px 1px 1px 0px rgba(0,0,0,0.14), 0px 1px 3px 0px rgba(0,0,0,0.12);
            --shadow-4: 0px 2px 4px -1px rgba(0,0,0,0.2), 0px 4px 5px 0px rgba(0,0,0,0.14), 0px 1px 10px 0px rgba(0,0,0,0.12);
            --shadow-6: 0px 3px 5px -1px rgba(0,0,0,0.2), 0px 6px 10px 0px rgba(0,0,0,0.14), 0px 1px 18px 0px rgba(0,0,0,0.12);
            --border-radius: 4px;
            --font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }

        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }

        body {
            font-family: var(--font-family);
            background-color: var(--background-default);
            color: var(--text-primary);
            line-height: 1.5;
            padding: 16px;
            display: flex;
            flex-direction: column;
            height: 100vh;
            overflow: hidden;
        }

        .gdpr-banner {
            position: sticky;
            top: 0;
            z-index: 100;
            margin-bottom: 16px;
            box-shadow: var(--shadow-6);
            background-color: var(--info-color);
            border-radius: var(--border-radius);
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 16px;
            width: 100%;
            color: white;
            text-align: center;
        }

        .gdpr-banner h2 {
            font-weight: 700;
            font-size: 1.25rem;
            letter-spacing: 0.02em;
        }

        .gdpr-banner a {
            color: #e3f2fd;
            font-weight: 700;
            text-decoration: underline;
            word-break: break-all;
        }

        .page-header {
            padding: 8px 16px;
            border-radius: var(--border-radius);
            margin-bottom: 16px;
            box-shadow: var(--shadow-4);
            background-color: var(--background-paper);
            display: flex;
            justify-content: center;
            align-items: center;
            flex-shrink: 0;
        }

        .page-header h1 {
            text-align: center;
            width: 100%;
            font-weight: 700;
            text-shadow: 0 2px 6px var(--grey-400), 0 1px 0 var(--grey-100), 0 0px 2px var(--primary-light);
            letter-spacing: 0.03em;
            margin-bottom: 0;
            font-size: 2rem;
        }

        .section-container {
            padding: 8px 16px;
            border-radius: var(--border-radius);
            display: flex;
            flex-direction: column;
            width: 100%;
            box-shadow: var(--shadow-1);
            background-color: var(--background-paper);
            margin-bottom: 16px;
        }

        .search-section {
            display: flex;
            flex-direction: row;
            align-items: center;
            gap: 16px;
            width: 100%;
            flex-shrink: 0;
        }

        @media (max-width: 768px) {
            .search-section {
                flex-direction: column;
                align-items: stretch;
            }
        }

        .search-input {
            min-width: 176px;
            flex: 1;
            height: 40px;
            padding: 8px 12px;
            border: 1px solid var(--divider-color);
            border-radius: var(--border-radius);
            font-size: 1rem;
            text-align: center;
        }

        .search-button {
            min-width: 112px;
            height: 40px;
            background-color: var(--primary-color);
            color: white;
            border: none;
            border-radius: var(--border-radius);
            font-size: 1rem;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
        }

        .search-button:disabled {
            background-color: var(--grey-400);
            cursor: not-allowed;
        }

        .table-section {
            flex: 1;
            min-height: 0;
            overflow: hidden;
            display: flex;
            flex-direction: column;
        }

        .data-table {
            width: 100%;
            border-collapse: collapse;
            flex: 1;
            display: block;
            overflow: auto;
        }

        .data-table thead {
            background-color: var(--grey-100);
            font-weight: bold;
            position: sticky;
            top: 0;
        }

        .data-table th {
            padding: 8px 16px;
            text-align: left;
            border-bottom: 1px solid var(--divider-color);
        }

        .data-table td {
            padding: 8px 16px;
            border-bottom: 1px solid var(--divider-color);
        }

        .data-table tbody tr:hover {
            background-color: rgba(0, 0, 0, 0.04);
        }

        .action-button {
            background: none;
            border: none;
            color: var(--primary-color);
            cursor: pointer;
            font-size: 0.875rem;
            display: inline-flex;
            align-items: center;
            gap: 4px;
            margin-right: 8px;
            padding: 4px 8px;
            border-radius: var(--border-radius);
        }

        .action-button:hover {
            background-color: rgba(25, 118, 210, 0.04);
        }

        .action-button.delete {
            color: var(--error-color);
        }

        .action-button.delete:hover {
            background-color: rgba(211, 47, 47, 0.04);
        }

        .action-button:disabled {
            color: var(--grey-400);
            cursor: not-allowed;
        }

        .loading-container {
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 16px;
        }

        .spinner {
            width: 22px;
            height: 22px;
            border: 2px solid transparent;
            border-top: 2px solid var(--primary-color);
            border-radius: 50%;
            animation: spin 1s linear infinite;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }

        .alert {
            padding: 12px 16px;
            border-radius: var(--border-radius);
            margin-bottom: 16px;
        }

        .alert.error {
            background-color: rgba(211, 47, 47, 0.1);
            color: var(--error-color);
            border: 1px solid var(--error-color);
        }

        .table-footer {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 8px 16px;
            border-top: 1px solid var(--divider-color);
            background-color: var(--grey-50);
        }

        .pagination {
            display: flex;
            gap: 8px;
        }

        .pagination-button {
            padding: 4px 8px;
            background: none;
            border: 1px solid var(--divider-color);
            border-radius: var(--border-radius);
            cursor: pointer;
        }

        .pagination-button:hover {
            background-color: rgba(0, 0, 0, 0.04);
        }

        .pagination-button:disabled {
            cursor: not-allowed;
            opacity: 0.5;
        }
    </style>
</head>
<body>
    <div class="gdpr-banner">
        <h2>
            Specific GDPR operation document:&nbsp;
            <a href="https://msasg.visualstudio.com/ContentServices/_wiki/wikis/BDT%20Engineering%20Wiki/335273/GDPR-Search" target="_blank" rel="noopener noreferrer">
                https://msasg.visualstudio.com/ContentServices/_wiki/wikis/BDT%20Engineering%20Wiki/335273/GDPR-Search
            </a>
        </h2>
    </div>

    <div class="page-header">
        <h1>Data search page</h1>
    </div>

    <div class="section-container search-section">
        <input type="text" class="search-input" id="phone-input" placeholder="Phone number">
        <input type="text" class="search-input" id="email-input" placeholder="Email address">
        <input type="text" class="search-input" id="address-input" placeholder="Address">
        <button class="search-button" id="search-button">
            <span id="search-button-text">Search</span>
        </button>
    </div>

    <div class="section-container table-section">
        <div id="error-container" class="alert error" style="display: none;"></div>
        
        <table class="data-table">
            <thead>
                <tr>
                    <th>Table Name</th>
                    <th>Have Data</th>
                    <th>Count</th>
                    <th>Actions</th>
                </tr>
            </thead>
            <tbody id="table-body">
                <!-- Table rows will be inserted here -->
            </tbody>
        </table>
        
        <div class="table-footer">
            <div class="pagination">
                <button class="pagination-button" id="prev-page" disabled>Previous</button>
                <button class="pagination-button" id="next-page" disabled>Next</button>
            </div>
            <div>Page <span id="current-page">1</span> of <span id="total-pages">1</span></div>
        </div>
    </div>

    <script>
        // 全局状态管理
        const state = {
            phone: '',
            email: '',
            address: '',
            loading: false,
            error: '',
            rows: [],
            exportLoadingId: null,
            currentPage: 1,
            pageSize: 10,
            totalPages: 1
        };

        // DOM 元素引用
        const elements = {
            phoneInput: document.getElementById('phone-input'),
            emailInput: document.getElementById('email-input'),
            addressInput: document.getElementById('address-input'),
            searchButton: document.getElementById('search-button'),
            searchButtonText: document.getElementById('search-button-text'),
            tableBody: document.getElementById('table-body'),
            errorContainer: document.getElementById('error-container'),
            prevPage: document.getElementById('prev-page'),
            nextPage: document.getElementById('next-page'),
            currentPage: document.getElementById('current-page'),
            totalPages: document.getElementById('total-pages')
        };

        // 表主键映射
        const tablePrimaryKey = {
            contact: "contactid",
            account: "accountid",
            systemuser: "systemuserid",
            customeraddress: "customeraddressid",
            leadaddress: "leadaddressid"
        };

        // 表选择字段映射
        const tableSelectFields = {
            contact: [
                "contactid", "emailaddress1", "firstname", "lastname", "_parentcustomerid_value",
                "address1_telephone1", "address1_telephone2", "address1_telephone3",
                "address2_telephone1", "address2_telephone2", "address2_telephone3",
                "address3_telephone1", "address3_telephone2", "address3_telephone3",
                "assistantphone", "ava_businessphone", "ava_mobilephone",
                "business2", "company", "home2", "managerphone",
                "mobilephone", "telephone1", "telephone2", "telephone3",
                "address1_composite", "address2_composite", "address3_composite",
                "emailaddress2", "emailaddress3"
            ],
            account: [
                "accountid",
                "address1_telephone2", "address1_telephone3",
                "address2_telephone1", "address2_telephone2", "address2_telephone3",
                "address1_telephone1", "telephone1", "telephone2", "telephone3",
                "address1_composite", "address2_composite",
                "emailaddress1", "emailaddress2", "emailaddress3",
                "address1_city", "address1_country", "address1_line1", "address1_line2", "address1_line3",
                "address2_city", "address2_country", "address2_line1", "address2_line2", "address2_line3"
            ],
            systemuser: [
                "systemuserid",
                "domainname",
                "fullname",
                "address1_telephone1", "address1_telephone2", "address1_telephone3",
                "address2_telephone1", "address2_telephone2", "address2_telephone3",
                "homephone", "mobilephone",
                "address1_composite",
                "internalemailaddress", "mobilealertemail", "personalemailaddress",
                "windowsliveid"
            ],
            customeraddress: [
                "customeraddressid",
                "name",
                "primarycontactname",
                "city",
                "county",
                "line1",
                "line2",
                "line3"
            ],
            leadaddress: [
                "city",
                "county",
                "line1",
                "line2",
                "line3",
                "name",
                "leadaddressid",
                "composite",
                "telephone1",
                "telephone2",
                "telephone3"
            ]
        };

        // 初始化事件监听器
        function initEventListeners() {
            elements.phoneInput.addEventListener('input', (e) => {
                state.phone = e.target.value;
            });

            elements.emailInput.addEventListener('input', (e) => {
                state.email = e.target.value;
            });

            elements.addressInput.addEventListener('input', (e) => {
                state.address = e.target.value;
            });

            elements.searchButton.addEventListener('click', handleSearch);

            elements.prevPage.addEventListener('click', () => {
                if (state.currentPage > 1) {
                    state.currentPage--;
                    renderTable();
                    updatePagination();
                }
            });

            elements.nextPage.addEventListener('click', () => {
                if (state.currentPage < state.totalPages) {
                    state.currentPage++;
                    renderTable();
                    updatePagination();
                }
            });
        }

        // 使用FetchXML获取数据
        function getDataByFetchXml(fetchXml, entityName) {
            return new Promise((resolve, reject) => {
                // 确保在D365环境中运行
                if (typeof Xrm === 'undefined' || !Xrm.Utility || !Xrm.Utility.getGlobalContext) {
                    reject(new Error("This application must run within a Dynamics 365 environment"));
                    return;
                }

                var req = new XMLHttpRequest();
                var url = Xrm.Utility.getGlobalContext().getClientUrl() + 
                         "/api/data/v9.1/" + entityName + 
                         "?fetchXml=" + encodeURIComponent(fetchXml);
                
                req.open("GET", url, true);
                req.setRequestHeader("OData-MaxVersion", "4.0");
                req.setRequestHeader("OData-Version", "4.0");
                req.setRequestHeader("Accept", "application/json");
                req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
                req.setRequestHeader("Prefer", "odata.include-annotations=\"*\"");
                
                req.onreadystatechange = function () {
                    if (this.readyState === 4) {
                        if (this.status === 200) {
                            var result = JSON.parse(this.response);
                            resolve(result.value);
                        } else {
                            reject(new Error(this.statusText || "Failed to fetch data"));
                        }
                    }
                };
                
                req.send();
            });
        }

        // 构建FetchXML过滤器辅助函数
        function buildPhoneFilter(table, value) {
            const trimmed = value.trim();
            if (!trimmed) return "";
            
            const variants = [];
            const noSpaces = trimmed.replace(/\s+/g, "");
            
            if (trimmed.startsWith("+")) {
                variants.push(trimmed);
                variants.push(trimmed.substring(1));
                variants.push(noSpaces);
                if (noSpaces.startsWith("+")) {
                    variants.push(noSpaces.substring(1));
                }
            } else {
                variants.push(trimmed);
                variants.push("+" + trimmed);
                variants.push(noSpaces);
                variants.push("+" + noSpaces);
            }
            
            const uniqueVariants = Array.from(new Set(variants));
            const fields = getPhoneFieldsForTable(table);
            
            const conditions = [];
            for (const field of fields) {
                for (const v of uniqueVariants) {
                    conditions.push(`<condition attribute="${field}" operator="eq" value="${v.replace(/'/g, "''")}" />`);
                }
            }
            
            if (conditions.length === 0) return "";
            return `<filter type="or">${conditions.join('')}</filter>`;
        }

        function getPhoneFieldsForTable(table) {
            if (table === "contact") {
                return [
                    "address1_telephone1", "address1_telephone2", "address1_telephone3",
                    "address2_telephone1", "address2_telephone2", "address2_telephone3",
                    "address3_telephone1", "address3_telephone2", "address3_telephone3",
                    "assistantphone", "ava_businessphone", "ava_mobilephone",
                    "business2", "company", "home2", "managerphone",
                    "mobilephone", "telephone1", "telephone2", "telephone3"
                ];
            } else if (table === "account") {
                return [
                    "address1_telephone2", "address1_telephone3",
                    "address2_telephone1", "address2_telephone2", "address2_telephone3",
                    "address1_telephone1", "telephone1", "telephone2", "telephone3"
                ];
            } else if (table === "systemuser") {
                return [
                    "address1_telephone1", "address1_telephone2", "address1_telephone3",
                    "address2_telephone1", "address2_telephone2", "address2_telephone3",
                    "homephone", "mobilephone"
                ];
            }
            return [];
        }

        function buildEmailFilter(table, value) {
            if (!value.trim()) return "";
            
            const fields = getEmailFieldsForTable(table);
            const conditions = fields.map(field => 
                `<condition attribute="${field}" operator="eq" value="${value.replace(/'/g, "''")}" />`
            );
            
            if (conditions.length === 0) return "";
            return `<filter type="or">${conditions.join('')}</filter>`;
        }

        function getEmailFieldsForTable(table) {
            if (table === "contact" || table === "account") {
                return ["emailaddress1", "emailaddress2", "emailaddress3"];
            } else if (table === "systemuser") {
                return [
                    "internalemailaddress", "mobilealertemail", "personalemailaddress",
                    "windowsliveid", "domainname"
                ];
            }
            return [];
        }

        function buildAddressFilter(table, value) {
            if (!value.trim()) return "";
            
            const fields = getAddressFieldsForTable(table);
            const conditions = fields.map(field => 
                `<condition attribute="${field}" operator="eq" value="${value.replace(/'/g, "''")}" />`
            );
            
            if (conditions.length === 0) return "";
            return `<filter type="or">${conditions.join('')}</filter>`;
        }

        function getAddressFieldsForTable(table) {
            if (table === "contact") {
                return ["address1_composite", "address2_composite", "address3_composite"];
            } else if (table === "account") {
                return [
                    "address1_composite", "address2_composite",
                    "address1_city", "address1_country", "address1_line1", "address1_line2", "address1_line3",
                    "address2_city", "address2_country", "address2_line1", "address2_line2", "address2_line3"
                ];
            } else if (table === "systemuser") {
                return ["address1_composite"];
            } else if (table === "customeraddress" || table === "leadaddress") {
                return ["line1", "line2", "line3"];
            }
            return [];
        }

        // 构建FetchXML查询
        function buildFetchXml(table, filters) {
            const pk = tablePrimaryKey[table];
            const entityFilter = filters ? `<filter type="and">${filters}</filter>` : '';
            
            return `
                <fetch mapping="logical">
                    <entity name="${table}">
                        <attribute name="${pk}" />
                        ${entityFilter}
                    </entity>
                </fetch>
            `.replace(/\s+/g, ' ').trim();
        }

        // 构建完整数据的FetchXML查询
        function buildFullDataFetchXml(table, filters) {
            const selectFields = Array.from(new Set(tableSelectFields[table]));
            const entityFilter = filters ? `<filter type="and">${filters}</filter>` : '';
            
            return `
                <fetch mapping="logical">
                    <entity name="${table}">
                        ${selectFields.map(field => `<attribute name="${field}" />`).join('')}
                        ${entityFilter}
                    </entity>
                </fetch>
            `.replace(/\s+/g, ' ').trim();
        }

        // 搜索处理函数
        async function handleSearch() {
            state.loading = true;
            state.error = '';
            state.rows = [];
            state.currentPage = 1;
            
            updateUI();
            
            try {
                const searchTables = ["contact", "account", "systemuser", "customeraddress", "leadaddress"];
                const allRows = [];
                
                for (const table of searchTables) {
                    const filters = [];
                    
                    // 构建过滤器
                    if (table === "contact" || table === "account" || table === "systemuser") {
                        if (state.phone.trim()) {
                            const phoneFilter = buildPhoneFilter(table, state.phone.trim());
                            if (phoneFilter) filters.push(phoneFilter);
                        }
                        if (state.email.trim()) {
                            const emailFilter = buildEmailFilter(table, state.email.trim());
                            if (emailFilter) filters.push(emailFilter);
                        }
                        if (state.address.trim()) {
                            const addressFilter = buildAddressFilter(table, state.address.trim());
                            if (addressFilter) filters.push(addressFilter);
                        }
                    } else {
                        if (state.address.trim()) {
                            const addressFilter = buildAddressFilter(table, state.address.trim());
                            if (addressFilter) filters.push(addressFilter);
                        }
                    }
                    
                    // 如果没有过滤器，跳过此表
                    if (filters.length === 0) continue;
                    
                    // 构建FetchXML并执行查询
                    const fetchXml = buildFetchXml(table, filters.join(''));
                    const result = await getDataByFetchXml(fetchXml, table);
                    
                    // 添加到显示行
                    allRows.push({
                        id: result.length > 0 ? result[0][tablePrimaryKey[table]] : table,
                        tableName: table,
                        haveData: result.length > 0,
                        count: result.length
                    });
                }
                
                state.rows = allRows;
                state.totalPages = Math.ceil(state.rows.length / state.pageSize);
            } catch (error) {
                state.error = error.message || "Failed to search data.";
            } finally {
                state.loading = false;
                updateUI();
            }
        }

        // 导出处理函数
        async function handleExport(row) {
            state.exportLoadingId = row.id;
            updateUI();
            
            try {
                const tableName = row.tableName;
                
                // 构建过滤器（与搜索时相同）
                const filters = [];
                
                if (tableName === "contact" || tableName === "account" || tableName === "systemuser") {
                    if (state.phone.trim()) {
                        const phoneFilter = buildPhoneFilter(tableName, state.phone.trim());
                        if (phoneFilter) filters.push(phoneFilter);
                    }
                    if (state.email.trim()) {
                        const emailFilter = buildEmailFilter(tableName, state.email.trim());
                        if (emailFilter) filters.push(emailFilter);
                    }
                    if (state.address.trim()) {
                        const addressFilter = buildAddressFilter(tableName, state.address.trim());
                        if (addressFilter) filters.push(addressFilter);
                    }
                } else {
                    if (state.address.trim()) {
                        const addressFilter = buildAddressFilter(tableName, state.address.trim());
                        if (addressFilter) filters.push(addressFilter);
                    }
                }
                
                if (filters.length === 0) {
                    state.exportLoadingId = null;
                    updateUI();
                    return;
                }
                
                // 构建完整的FetchXML查询（包含所有字段）
                const fetchXml = buildFullDataFetchXml(tableName, filters.join(''));
                
                // 执行查询
                const result = await getDataByFetchXml(fetchXml, tableName);
                
                // 构建导出数据
                const exportRecords = result.map(record => {
                    const props = {};
                    for (const field of tableSelectFields[tableName]) {
                        props[field] = record[field] ?? null;
                    }
                    return props;
                });
                
                // 生成当前时间
                const now = new Date();
                const time = now.toISOString();
                
                // 生成相关ID
                let correlationId = "";
                if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
                    correlationId = crypto.randomUUID();
                } else {
                    correlationId = Math.random().toString(36).substring(2) + Date.now();
                }
                
                // 构建JSON负载
                const payload = {
                    time,
                    correlationId,
                    table: tableName,
                    count: exportRecords.length,
                    records: exportRecords,
                };
                
                // 转换为JSON字符串
                const jsonStr = JSON.stringify(payload, null, 2);
                
                // 创建Blob并触发下载
                const blob = new Blob([jsonStr], { type: "text/plain" });
                const url = URL.createObjectURL(blob);
                
                // 创建文件名
                const fileName = `export_${tableName}_${now.getTime()}.txt`;
                
                // 创建下载链接并触发点击
                const a = document.createElement("a");
                a.href = url;
                a.download = fileName;
                document.body.appendChild(a);
                a.click();
                setTimeout(() => {
                    document.body.removeChild(a);
                    URL.revokeObjectURL(url);
                }, 100);
            } catch (error) {
                state.error = error.message || "Failed to export data.";
                updateUI();
            } finally {
                state.exportLoadingId = null;
                updateUI();
            }
        }

        // 删除处理函数
        function handleDelete(row) {
            const confirmText = `Do you wish to send a deletion request to the BDT Team regarding the table: ${row.tableName}? If you select Yes, the system will automatically open Outlook and populate the relevant email information. You will need to manually click Send for the email to be sent. If Outlook is not open, please contact: bdtproduct@microsoft.com`;
            
            if (confirm(confirmText)) {
                const subject = encodeURIComponent("GDPR ICM Ticket: Delete Data Request");
                const body = encodeURIComponent(
                    `Please delete the following data:\n\nTable Name: ${row.tableName}\nData IDs:\n${row.id}\n`
                );
                const mailto = `mailto:bdteng@microsoft.com?subject=${subject}&body=${body}`;
                window.open(mailto, "_blank");
                alert("Your email client has been opened. Please send the email to complete the deletion request.");
            }
        }

        // 更新UI
        function updateUI() {
            // 更新搜索按钮状态
            if (state.loading) {
                elements.searchButton.disabled = true;
                elements.searchButtonText.innerHTML = '<div class="spinner"></div>';
            } else {
                elements.searchButton.disabled = false;
                elements.searchButtonText.textContent = 'Search';
            }
            
            // 显示或隐藏错误信息
            if (state.error) {
                elements.errorContainer.style.display = 'block';
                elements.errorContainer.textContent = state.error;
            } else {
                elements.errorContainer.style.display = 'none';
            }
            
            // 渲染表格
            renderTable();
            
            // 更新分页控件
            updatePagination();
        }

        // 渲染表格
        function renderTable() {
            elements.tableBody.innerHTML = '';
            
            if (state.rows.length === 0) {
                const row = document.createElement('tr');
                row.innerHTML = `
                    <td colspan="4" style="text-align: center; padding: 20px;">
                        ${state.loading ? 'Searching...' : 'No data available. Please perform a search.'}
                    </td>
                `;
                elements.tableBody.appendChild(row);
                return;
            }
            
            // 计算分页数据
            const startIndex = (state.currentPage - 1) * state.pageSize;
            const endIndex = Math.min(startIndex + state.pageSize, state.rows.length);
            const pageRows = state.rows.slice(startIndex, endIndex);
            
            pageRows.forEach(row => {
                const tr = document.createElement('tr');
                
                // 表名列
                const tdTable = document.createElement('td');
                tdTable.textContent = row.tableName;
                tr.appendChild(tdTable);
                
                // 是否有数据列
                const tdHaveData = document.createElement('td');
                tdHaveData.textContent = row.haveData ? 'Yes' : 'No';
                if (row.haveData) {
                    tdHaveData.style.color = 'var(--primary-color)';
                } else {
                    tdHaveData.style.color = 'var(--text-secondary)';
                }
                tr.appendChild(tdHaveData);
                
                // 计数列
                const tdCount = document.createElement('td');
                tdCount.textContent = row.count;
                tr.appendChild(tdCount);
                
                // 操作列
                const tdActions = document.createElement('td');
                
                const exportButton = document.createElement('button');
                exportButton.className = 'action-button';
                exportButton.disabled = !!state.exportLoadingId;
                
                if (state.exportLoadingId === row.id) {
                    exportButton.innerHTML = '<div class="spinner" style="width: 18px; height: 18px;"></div> Export';
                } else {
                    exportButton.innerHTML = '📥 Export';
                }
                
                exportButton.addEventListener('click', () => handleExport(row));
                tdActions.appendChild(exportButton);
                
                const deleteButton = document.createElement('button');
                deleteButton.className = 'action-button delete';
                deleteButton.disabled = !!state.exportLoadingId;
                deleteButton.innerHTML = '🗑️ Delete';
                deleteButton.addEventListener('click', () => handleDelete(row));
                tdActions.appendChild(deleteButton);
                
                tr.appendChild(tdActions);
                
                elements.tableBody.appendChild(tr);
            });
        }

        // 更新分页控件
        function updatePagination() {
            elements.currentPage.textContent = state.currentPage;
            elements.totalPages.textContent = state.totalPages;
            
            elements.prevPage.disabled = state.currentPage <= 1;
            elements.nextPage.disabled = state.currentPage >= state.totalPages;
            
            // 只有在有数据时才显示分页
            elements.prevPage.style.visibility = state.rows.length > 0 ? 'visible' : 'hidden';
            elements.nextPage.style.visibility = state.rows.length > 0 ? 'visible' : 'hidden';
        }

        // 初始化应用
        function initApp() {
            initEventListeners();
            updateUI();
        }

        // 启动应用
        document.addEventListener('DOMContentLoaded', initApp);
    </script>
</body>
</html>